package xerr

import (
	"encoding/json"

	"github.com/gogf/gf/encoding/gjson"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/util/gconv"
	"github.com/pkg/errors"
	"google.golang.org/grpc/status"
)

var AppCode = 0

type CodeError struct {
	errCode int
	errMsg  string
}

// 属性
func (e *CodeError) GetErrCode() int {
	return e.errCode
}

func (e *CodeError) GetErrMsg() string {
	return e.errMsg
}

func (e *CodeError) Error() string {
	data := g.Map{"ErrCode": e.errCode, "ErrMsg": e.errMsg}
	dataJson, _ := json.Marshal(data)
	return string(dataJson)
	//return fmt.Sprintf("ErrCode:%d，ErrMsg:%s", e.errCode, e.errMsg)
}

func newError(errCode ERROR_TYPE, errMsg string) *CodeError {

	errcodeNEw := int(errCode)
	if AppCode != 0 {
		errcodeNEw = 1000*AppCode + errcodeNEw
	}
	return &CodeError{errCode: errcodeNEw, errMsg: errMsg}
}

func newErrorWithOrgCode(errCode int, errMsg string) *CodeError {
	return &CodeError{errCode: errCode, errMsg: errMsg}
}

func NewReturnValError(errMsg string) *CodeError {
	return newError(ERROR_TYPE_RETURNVAR, errMsg)
}

func NewDBError(errMsg string) *CodeError {
	return newError(ERROR_TYPE_DB, errMsg)
}

func NewParamError(errMsg string) *CodeError {
	return newError(ERROR_TYPE_PARAM, errMsg)
}

func NewLogicError(errMsg string) *CodeError {
	return newError(ERROR_TYPE_LOGIC, errMsg)
}

func NewRedisLockError(errMsg string) *CodeError {
	return newError(ERROR_TYPE_REDIS_LOCK, errMsg)
}

func NewRedisError(errMsg string) *CodeError {
	return newError(ERROR_TYPE_REDIS, errMsg)
}

func NewOssError(errMsg string) *CodeError {
	return newError(ERROR_TYPE_OSS, errMsg)
}

func NewPerDenyError(errMsg string) *CodeError {
	return newError(ERROR_TYPE_PERMDENY, errMsg)
}

func NewThirdPartyError(errMsg string) *CodeError {
	return newError(ERROR_THIRDPART_ERROR, errMsg)
}

func NewOtherError(errMsg string) *CodeError {
	return newError(ERROR_TYPE_OTHER, errMsg)
}

func NewRpcErrorFromTxt(msg string) *CodeError {
	return newError(ERROR_TYPE_RPC, msg)
}

func NewRpcErrorFromErr(err error) *CodeError {
	errmsg := err.Error()
	errcode := 0

	originErr := errors.Cause(err) // err类型
	if gstatus, ok := status.FromError(originErr); ok {
		// grpc err错误
		errmsg = gstatus.Message()
		jobj, errJson := gjson.LoadContent(errmsg)
		if errJson == nil && jobj.Contains("ErrCode") {
			errcode = jobj.GetInt("ErrCode")
			errmsg = jobj.GetString("ErrMsg")
			errCodeFrom := ERROR_TYPE(errcode % 1000)
			if errCodeFrom != ERROR_TYPE_PARAM && errCodeFrom != ERROR_TYPE_LOGIC {
				errCodeFrom = ERROR_TYPE_RPC
				errmsg += " /" + gconv.String(errcode)
			}
			return newError(errCodeFrom, errmsg)
		}
	}
	return newError(ERROR_TYPE_RPC, errmsg)
}

func NewNoDataFoundTypeError(msg string) *CodeError {
	return newError(ERROR_TYPE_NODATA_FOUND, msg)
}

func GetErrorType(err error) ERROR_TYPE {
	// errmsg := err.Error()
	errcode := 0
	originErr := errors.Cause(err) // err类型
	if gstatus, ok := status.FromError(originErr); ok {
		// grpc err错误
		// errmsg = gstatus.Message()
		errmsg := gstatus.Message()
		jobj, errJson := gjson.LoadContent(errmsg)
		if errJson == nil && jobj.Contains("ErrCode") {
			errcode = jobj.GetInt("ErrCode")
			// errmsg = jobj.GetString("ErrMsg")
			errCodeFrom := ERROR_TYPE(errcode % 1000)
			return errCodeFrom
		}
	}
	return ERROR_TYPE_UNKONW
}

//
//func NewErrCode(errCode int) *CodeError {
//	return &CodeError{errCode: errCode, errMsg: MapErrMsg(errCode)}
//}
//
//func NewErrMsg(errMsg string) *CodeError {
//	return &CodeError{errCode: BAD_REUQEST_ERROR, errMsg: errMsg}
//}
